from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework_simplejwt.authentication import JWTAuthentication
from django.db.models import Q
from django.utils.dateparse import parse_datetime
from django.shortcuts import get_object_or_404
from system.models import Role, Menu, UserRole, RoleMenu
from system.SysUtils.permission import permission_required, data_permission_required
from .roles_serializers import RolePageSerializer, MenuOptionSerializer, RoleCreateSerializer, RoleFormSerializer
from django.utils import timezone
from django.db import transaction


class RolePageView(APIView):
    """角色分页查询视图"""
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]

    @permission_required(["sys:role:query"])
    def get(self, request, *args, **kwargs):
        """
        获取角色分页列表
        
        查询参数:
        - keywords: 关键字(角色名称/角色编码)
        - startDate: 开始日期
        - endDate: 结束日期 
        - pageNum: 页码
        - pageSize: 每页记录数
        """
        # 获取查询参数
        keywords = request.query_params.get('keywords', '')
        start_date = request.query_params.get('startDate')
        end_date = request.query_params.get('endDate')
        page_num = int(request.query_params.get('pageNum', 1))
        page_size = int(request.query_params.get('pageSize', 10))

        # 获取数据权限范围
        token = request.headers.get("Authorization")
        data_permission = data_permission_required(token, "select")

        # 构建查询条件
        query = Q(is_deleted=0)  # 只查询未删除的角色

        # 添加数据权限过滤
        if isinstance(data_permission, list) and data_permission:
            # 如果返回的是用户ID列表，只查询这些用户创建的角色
            query &= Q(create_by__in=data_permission)

        # 关键字查询
        if keywords:
            query &= Q(name__icontains=keywords) | Q(code__icontains=keywords)

        # 日期范围查询
        if start_date and end_date:
            start_date_time = parse_datetime(start_date)
            end_date_time = parse_datetime(end_date)
            if start_date_time and end_date_time:
                query &= Q(create_time__gte=start_date_time, create_time__lte=end_date_time)

        # 查询角色总数
        total = Role.objects.filter(query).count()

        # 分页查询
        start = (page_num - 1) * page_size
        end = start + page_size

        roles = Role.objects.filter(query).order_by('sort', 'id')[start:end]

        # 序列化
        serializer = RolePageSerializer(roles, many=True)

        # 返回数据
        return Response({
            "code": "00000",
            "data": {
                "list": serializer.data,
                "total": total
            },
            "msg": "获取角色列表成功"
        })


class RoleFormView(APIView):
    """角色表单信息视图"""
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]

    @permission_required(["sys:role:edit"])
    def get(self, request, role_id, *args, **kwargs):
        """
        获取角色表单信息
        
        路径参数:
        - role_id: 角色ID
        """
        # 获取角色信息
        role = get_object_or_404(Role, id=role_id, is_deleted=0)

        # 获取数据权限，传入角色的创建者ID
        token = request.headers.get("Authorization")
        creator_id = role.create_by
        has_permission = data_permission_required(token, "update", creator_id)

        # 验证是否有权限更新此角色
        if not has_permission:
            return Response({
                "code": "A0403",
                "msg": "您没有权限编辑此角色"
            }, status=403)

        # 序列化
        serializer = RoleFormSerializer(role)

        # 返回数据
        return Response({
            "code": "00000",
            "data": serializer.data,
            "msg": "获取角色表单信息成功"
        })


class RoleMenuIdsView(APIView):
    """角色关联菜单ID查询视图"""
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]

    @permission_required(["sys:menu:query"])
    def get(self, request, role_id, *args, **kwargs):
        """
        获取指定角色的菜单ID列表
        
        路径参数:
        - role_id: 角色ID
        """
        # 验证角色是否存在且未被删除
        get_object_or_404(Role, id=role_id, is_deleted=0)
        
        # 获取该角色关联的所有菜单ID
        menu_ids = RoleMenu.objects.filter(role_id=role_id).values_list('menu_id', flat=True)
        
        # 将整数ID转换为字符串格式
        menu_ids_str = [str(menu_id) for menu_id in menu_ids]
        
        # 返回数据
        return Response({
            "code": "00000",
            "data": menu_ids_str,
            "msg": "一切ok"
        })


class RoleMenusView(APIView):
    """角色菜单分配视图"""
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]
    
    @permission_required(["sys:role:edit"])
    def put(self, request, role_id, *args, **kwargs):
        """
        分配菜单权限给角色
        
        路径参数:
        - role_id: 角色ID
        
        请求体:
        - 菜单ID列表，如: ["1", "2", "3", "4"]
        """
        # 验证角色是否存在且未被删除
        role = get_object_or_404(Role, id=role_id, is_deleted=0)
        
        # 获取数据权限，传入角色的创建者ID
        token = request.headers.get("Authorization")
        creator_id = role.create_by
        has_permission = data_permission_required(token, "update", creator_id)
        
        # 验证是否有权限更新此角色
        if not has_permission:
            return Response({
                "code": "A0403",
                "msg": "您没有权限分配此角色的菜单权限"
            }, status=403)
        
        # 获取请求中的菜单ID列表
        menu_ids = request.data
        
        # 验证菜单ID格式
        try:
            menu_id_list = [int(menu_id) for menu_id in menu_ids if menu_id]
        except (ValueError, TypeError):
            return Response({
                "code": "A0400",
                "msg": "菜单ID格式不正确"
            }, status=400)
        
        # 验证菜单是否存在
        existing_menu_ids = set(Menu.objects.filter(id__in=menu_id_list).values_list('id', flat=True))
        invalid_menu_ids = [str(menu_id) for menu_id in menu_id_list if menu_id not in existing_menu_ids]
        
        if invalid_menu_ids:
            return Response({
                "code": "A0400",
                "msg": f"以下菜单ID不存在: {', '.join(invalid_menu_ids)}"
            }, status=400)
        
        # 使用事务确保数据一致性
        with transaction.atomic():
            # 删除原有的角色-菜单关联
            RoleMenu.objects.filter(role_id=role_id).delete()
            
            # 创建新的角色-菜单关联
            role_menu_objs = [
                RoleMenu(role_id=role_id, menu_id=menu_id)
                for menu_id in menu_id_list
            ]
            
            if role_menu_objs:
                RoleMenu.objects.bulk_create(role_menu_objs)
            
            # 更新角色的更新时间和更新人
            if hasattr(request, 'user') and request.user:
                role.update_by = request.user.id
                role.update_time = timezone.now()
                role.save(update_fields=['update_by', 'update_time'])
        
        # 返回成功响应
        return Response({
            "code": "00000",
            "data": {},
            "msg": "菜单权限分配成功"
        })


class RoleView(APIView):
    """角色管理视图"""
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]

    @permission_required(["sys:role:add"])
    def post(self, request, *args, **kwargs):
        """
        新增角色
        
        请求体参数:
        - name: 角色名称（必需）
        - code: 角色编码（必需）
        - sort: 排序（可选）
        - status: 角色状态(1-正常；0-停用)（可选，默认1）
        - dataScope: 数据权限（可选）
        """
        # 获取请求中的角色名称和编码
        name = request.data.get('name')
        code = request.data.get('code')

        # 检查是否存在未删除的同名或同编码角色
        if Role.objects.filter(Q(name=name) | Q(code=code), is_deleted=0).exists():
            return Response({
                "code": "A0400",
                "msg": "角色名称或编码已存在"
            }, status=400)

        # 检查是否存在已删除的同名和同编码角色
        deleted_role = Role.objects.filter(name=name, code=code, is_deleted=1).first()
        if deleted_role:
            # 如果存在，则恢复该角色
            deleted_role.is_deleted = 0
            deleted_role.create_by = request.user.id if hasattr(request, 'user') and request.user else None
            deleted_role.create_time = timezone.now()
            deleted_role.update_by = None
            deleted_role.update_time = None

            # 更新其他字段
            if 'sort' in request.data:
                deleted_role.sort = request.data.get('sort')
            if 'status' in request.data:
                deleted_role.status = request.data.get('status')
            if 'dataScope' in request.data:
                deleted_role.data_scope = request.data.get('dataScope')

            deleted_role.save()

            # 返回成功响应，包含恢复的角色数据
            role_data = RoleFormSerializer(deleted_role).data
            return Response({
                "code": "00000",
                "data": role_data,
                "msg": "角色创建成功"
            })

        # 检查是否存在已删除的同名或同编码角色（只有一个相同）
        if Role.objects.filter(Q(name=name) | Q(code=code), is_deleted=1).exists():
            return Response({
                "code": "A0400",
                "msg": "角色名称或编码已存在（在已删除的角色中）"
            }, status=400)

        # 使用序列化器验证请求数据
        serializer = RoleCreateSerializer(data=request.data, context={'request': request})

        if serializer.is_valid():
            # 创建角色
            role = serializer.save()

            # 返回成功响应，包含新创建的角色数据
            role_data = RoleFormSerializer(role).data
            return Response({
                "code": "00000",
                "data": role_data,
                "msg": "角色创建成功"
            })
        else:
            # 返回验证错误信息
            return Response({
                "code": "A0400",
                "msg": serializer.errors
            }, status=400)

    @permission_required(["sys:role:edit"])
    def put(self, request, role_id, *args, **kwargs):
        """
        更新角色信息
        
        路径参数:
        - role_id: 角色ID
        
        请求体参数:
        - name: 角色名称（必需）
        - code: 角色编码（必需）
        - sort: 排序（可选）
        - status: 角色状态(1-正常；0-停用)（可选）
        - dataScope: 数据权限（可选）
        """
        # 获取角色信息
        role = get_object_or_404(Role, id=role_id, is_deleted=0)

        # 获取数据权限，传入角色的创建者ID
        token = request.headers.get("Authorization")
        creator_id = role.create_by
        has_permission = data_permission_required(token, "update", creator_id)

        # 验证是否有权限更新此角色
        if not has_permission:
            return Response({
                "code": "A0403",
                "msg": "您没有权限编辑此角色"
            }, status=403)

        # 使用RoleFormSerializer验证和更新数据
        # 确保request.data中包含id字段
        data = request.data.copy()
        data['id'] = role_id

        serializer = RoleFormSerializer(role, data=data, partial=True)

        if serializer.is_valid():
            # 更新角色
            updated_role = serializer.save()

            # 设置更新人ID
            if hasattr(request, 'user') and request.user:
                updated_role.update_by = request.user.id
                updated_role.save(update_fields=['update_by'])

            # 返回成功响应，包含更新后的角色数据
            updated_data = RoleFormSerializer(updated_role).data
            return Response({
                "code": "00000",
                "data": updated_data,
                "msg": "角色更新成功"
            })
        else:
            # 返回验证错误信息
            return Response({
                "code": "A0400",
                "msg": serializer.errors
            }, status=400)

    @permission_required(["sys:role:delete"])
    def delete(self, request, role_id, *args, **kwargs):
        """
        删除角色
        
        路径参数:
        - role_id: 角色ID，可以是单个ID或多个以英文逗号(,)拼接的ID
        """
        # 获取当前用户令牌
        token = request.headers.get("Authorization")

        # 处理传入的role_id
        role_ids = str(role_id)  # 确保转换为字符串

        # 处理单个ID的情况
        if role_ids.isdigit():
            id_list = [int(role_ids)]
        else:
            # 解析角色ID列表
            id_list = [int(id_str) for id_str in role_ids.split(',') if id_str.isdigit()]

        if not id_list:
            return Response({
                "code": "A0400",
                "msg": "无效的角色ID"
            }, status=400)

        # 查询所有要删除的角色
        roles = Role.objects.filter(id__in=id_list, is_deleted=0)

        # 检查角色是否已分配给用户
        for role in roles:
            # 检查是否有用户关联到该角色
            if UserRole.objects.filter(role_id=role.id).exists():
                return Response({
                    "code": "A0400",
                    "msg": f"角色【{role.name}】已分配用户，请先解除关联后删除"
                }, status=400)

        # 检查数据权限
        authorized_roles = []
        unauthorized_roles = []

        for role in roles:
            # 获取数据权限，传入角色的创建者ID
            has_permission = data_permission_required(token, "delete", role.create_by)

            if has_permission:
                authorized_roles.append(role)
            else:
                unauthorized_roles.append(role.name)

        # 如果有未授权的角色，返回错误信息
        if unauthorized_roles:
            return Response({
                "code": "A0403",
                "msg": f"您没有权限删除以下角色: {', '.join(unauthorized_roles)}"
            }, status=403)

        # 执行逻辑删除（将is_deleted设置为1）
        # 获取当前用户作为更新人
        update_by = request.user.id if hasattr(request, 'user') and request.user else None

        for role in authorized_roles:
            role.is_deleted = 1
            if update_by:
                role.update_by = update_by
            role.save(update_fields=['is_deleted', 'update_by'])

        # 返回成功响应
        return Response({
            "code": "00000",
            "data": {},
            "msg": f"成功删除 {len(authorized_roles)} 个角色"
        })


class RoleOptionsView(APIView):
    """角色下拉列表视图"""
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]

    def get(self, request, *args, **kwargs):
        """
        获取角色下拉列表
        
        返回所有可用角色的下拉选项列表。
        """
        # 查询所有未删除且状态正常的角色，按排序字段排序
        roles = Role.objects.filter(is_deleted=0, status=1).order_by('sort', 'id')

        # 构建选项列表
        options = []
        for role in roles:
            option = {
                "value": role.id,
                "label": role.name,
                "tag": "success" if role.status == 1 else "danger"
            }
            options.append(option)

        # 返回数据
        return Response({
            "code": "00000",
            "data": options,
            "msg": "获取角色下拉列表成功"
        })
